#include <map>
#include <sstream>
#include <iostream>
#include <unistd.h>
#include <arpa/inet.h>

#include "parser.h"
#include "serial.hpp"
#include "helper.hpp"
#include "interface.hpp"
#include "fingerprint.hpp"
#include "config_parser.hpp"

extern std::map<int, User> users;
extern std::map<unsigned int, Base*> gids;
extern std::map<unsigned int, Mode> modes;
extern std::map<unsigned int, Panel> panels;
extern std::map<unsigned int, Sensor> sensors;
extern std::map<unsigned int, Serial> port_map;
extern std::map<unsigned int, Command> commands;
extern std::map<unsigned int, Timer> user_timers;

/* GSM class implementation */
void Gsm::set(std::string v) 
{
    char *msg;
    char resp[256];
    std::string msg_num;

    pthread_mutex_lock(&this->set_get_mutex);

    msg_num = "AT+CMGS=\"" + this->number + "\"";

    msg = (char*)malloc(msg_num.size() + 2);
    strcpy(msg, msg_num.c_str());
    gsm_write(msg);
    free(msg);

    usleep(200000);
    gsm_read(resp);

    msg = (char*)malloc(this->text.size() + 2);
    strcpy(msg, this->text.c_str());
    logger(SM_LOG_INFO,"sending msg = %s", msg);

    for(size_t i = 0; i < strlen(msg); ++i){
        if(msg[i] == '^') {
            msg[i] = 10;
        }
    }

    gsm_write(msg);
    free(msg);
    usleep(300000);
    gsm_read(resp);

    char ctrl_z[4];
    ctrl_z[0] = 0x1A;
    ctrl_z[1] = 0;

    /* finish the msg */
    gsm_write(ctrl_z);
    pthread_mutex_unlock(&this->set_get_mutex);
}

std::string Gsm::get() 
{
    return "gsm";
}

Sensor::Sensor() 
{
    this->save_attribute = NULL;
    pthread_mutex_init(&this->set_get_mutex, NULL); 
}

void Sensor::set(std::string v)
{

    double current_value = atof(this->value.c_str());
    double new_value = atof(v.c_str());

    if(current_value != new_value) {
        pthread_mutex_lock(&this->set_get_mutex);
        this->value = v;
        pthread_mutex_unlock(&this->set_get_mutex);

        // if this->ivent_handler == 0 then no ivent_hanler was specified.
        if(this->ivent_handler != 0) {
            logger(SM_LOG_INFO, CCYN "%5s[%d]" CRED " ---> " CMAG "GID[%d] - value[%s]" CNRM, 
                    "IVENT", this->gid, this->ivent_handler, v.c_str());
            gids[this->ivent_handler]->set(v);
        }
    }
}

std::string Sensor::get()
{   
    std::string v;
    pthread_mutex_lock(&this->set_get_mutex);
    v = this->value;
    pthread_mutex_unlock(&this->set_get_mutex);
    return v;
}

/* Base Class implementation used only for Var types. */
Base::Base()
{ 
    this->save_attribute = NULL;
    pthread_mutex_init(&this->set_get_mutex, NULL); 
}
void Base::set(std::string v)
{
    pthread_mutex_lock(&this->set_get_mutex);
    // check if we are in the virtual mode.
    if(v[0] == '#') 
        this->value = v.substr(1);
    else
        this->value = v;

    if(this->save_attribute) {
        this->save_attribute->set_value(v);
        save_config();
    }
    pthread_mutex_unlock(&this->set_get_mutex);
}

std::string Base::get()
{   
    std::string v;
    pthread_mutex_lock(&this->set_get_mutex);
    v = this->value;
    pthread_mutex_unlock(&this->set_get_mutex);
    return v;
}

/* Panel implementation */
void Panel::start_timer()
{
    timer_settime(this->timerid, 0, &this->timeout, NULL);
}

void Panel::init()
{   
    b_packet_t *req;
    p_packet_t *resp;

    int retry_count = 10;
    req = str_to_pkt(this->init_data);

retry:
    retry_count--;
    resp = (p_packet_t*)rt_send_request(this->port, req);

    if(!resp) {
        logger(SM_LOG_ERR,"ERROR INITING PANEL: = retrying, count = %d...", (10 - retry_count));
        if(retry_count == 0) {
            free(req);
            return;
        }
        usleep(100000);
        goto retry;
    }

    std::string resp_str = pkt_to_str((b_packet_t*)resp);
    std::string req_str = pkt_to_str((b_packet_t*)req);

    if(resp->size < 7 || (resp->size != 7 && (resp->size - 7) % 3 != 0)) {
       logger(SM_LOG_ERR, "INIT_PANEL: WRONG packet received: request = [%s], response = [%s]", 
               req_str.c_str(), resp_str.c_str());
       goto retry;
    }

    for(size_t i = 0; i < this->sensors.size(); i++) {
        float v = -1;
        switch(this->sensors[i]->type) {
            case CONTACT: 
                v = get_contact(resp, this->sensors[i]->id);
                break;
            case BUTTON: 
                v = get_button(resp, this->sensors[i]->id);
                break;
            case DIGITAL: 
                v = get_digital(resp, this->sensors[i]->id);
                if(v == -1) {
                    v = atof(this->sensors[i]->get().c_str());
                }
                break;
            default:
                break;
        }
        this->sensors[i]->value = to_string(v);
        logger(SM_LOG_INFO,"INIT_PANEL[%d] ---> [%.02f] req[%s] resp[%s]", 
                this->sensors[i]->gid, v, req_str.c_str(), resp_str.c_str());
    }
    free(req);
    free(resp);
}

void* Panel::update_routine(void* obj)
{   
    b_packet_t *req;
    p_packet_t *resp;
    Panel *p = (Panel*)obj;
    struct itimerspec curr_value;

    pthread_detach(pthread_self());
    req = str_to_pkt(p->update_data);
    // Wait until panel's state becomes true.
    while(!p->state){
        sleep(1);
    }
    p->start_timer();
    for(;;){
        // Wait until panel's state becomes true.
        while(!p->state){
            sleep(1);
        }
        timer_gettime(p->timerid, &curr_value);
        if((!curr_value.it_value.tv_sec && !curr_value.it_value.tv_nsec)){
            p->start_timer();
        } else {
            nanosleep(&curr_value.it_value, NULL);
            continue;
        }

        resp = (p_packet_t*)rt_send_request(p->port, req);

        if(!resp) {
            continue;
        }

        std::string resp_str = pkt_to_str((b_packet_t*)resp);
        std::string req_str = pkt_to_str((b_packet_t*)req);

        if(resp->size < 7 || (resp->size != 7 && (resp->size - 7) % 3 != 0)) {
            logger(SM_LOG_ERR, "UPDATE: WRONG packet received: request = [%s], response = [%s]", 
                req_str.c_str(), resp_str.c_str());
            continue;
        }

        for(size_t i = 0; i < p->sensors.size(); i++) {
            double new_value = 0;
            double current_value = atof(p->sensors[i]->get().c_str());
            switch(p->sensors[i]->type) {
                case CONTACT: 
                    new_value = get_contact(resp, p->sensors[i]->id);
                    break;
                case BUTTON: 
                    new_value = get_button(resp, p->sensors[i]->id);
                    break;
                case DIGITAL: 
                    new_value = get_digital(resp, p->sensors[i]->id);
                    if(new_value == -1)
                        continue;
                    break;
            }
            if (current_value != new_value){
                logger(SM_LOG_INFO,"UPDATE[%d] ---> [%.02f] req[%s] resp[%s]", 
                        p->sensors[i]->gid, new_value, req_str.c_str(), resp_str.c_str());
                p->sensors[i]->set(to_string((float)new_value));
            }
        }
        free(resp);
    }
    free(req);
    pthread_exit(NULL);
}

void Panel::set(std::string v)
{
    pthread_mutex_lock(&this->set_get_mutex);
    if(v == "on") {
        this->state = true;
    } else {
        this->state = false;
    }
    logger(SM_LOG_INFO,"PANEL[%d] ---> state[%s]", this->gid, this->state ? "on" : "off");
    pthread_mutex_unlock(&this->set_get_mutex);
}

std::string Panel::get()
{
    pthread_mutex_lock(&this->set_get_mutex);
    std::string v;
    this->state ? v = "on" : v = "off";
    pthread_mutex_unlock(&this->set_get_mutex);
    return v;
}

void Panel::update()
{
    pthread_create(&this->thread, NULL, &Panel::update_routine,
            static_cast<void*>(this));
}

/* Command Class implementation */

Command::Command()
{
    get_mode = FAST;
    set_mode = SLOW;
    pthread_mutex_init(&this->set_get_mutex, NULL);
}
void Command::set(std::string v)
{
    // check if we are in the virtual mode.
    if(v[0] == '#') {
        pthread_mutex_lock(&this->set_get_mutex);
        this->value = v.substr(1);
        logger(SM_LOG_INFO,"Virtually changed the [g%d] Command's value to %s",
                this->gid, this->value.c_str());
        pthread_mutex_unlock(&this->set_get_mutex);
        return;
    }

    pthread_mutex_lock(&this->set_get_mutex);
    b_packet_t *req, *resp;
    std::string data = this->data_for_set;

    find_and_replace(data, "value", v);

    /* find and replace g* string with it's value. */
    replace_ids_to_values(this->data_gids, data);

    req = str_to_pkt(data);

    if(this->set_mode == SLOW) {
        resp = rt_send_request(this->port, req);

        if(!resp) {
            free(req);
            pthread_mutex_unlock(&this->set_get_mutex);
            return;
        }
        free(resp);
    } else {
        /* only write if we are on FAST 'set' mode. */
        rt_write(this->port, req);
    }

    free(req);
    this->value = v;

    for(size_t i = 0; i < this->connections.size(); i++) {
        gids[this->connections[i].first]->set(string("#") +
                gids[this->connections[i].second]->get());
    }

    pthread_mutex_unlock(&this->set_get_mutex);
}

std::string Command::get()
{   
    pthread_mutex_lock(&this->set_get_mutex);
    std::string v = "0";
    if(this->get_mode == SLOW) {
        uint32_t tmp_value = 0;
        b_packet_t *req, *resp;

        req = str_to_pkt(this->data_for_get);
        resp = rt_send_request(this->port, req);

        if(!resp) {
            free(req);
            logger(SM_LOG_ERR,"Can't read response from the device, returning '-1'");
            pthread_mutex_unlock(&this->set_get_mutex);
            return "-1";
        }

        if((int)(this->start_byte + this->bytes_to_get - 2) >= (int)(resp->size + 3)) {
            logger(SM_LOG_ERR,"CMD GET ERROR: WRONG data RCVD in CMD GET SLOW mode, pkt[%s] "
                    "data_for_get[%s]", pkt_to_str(resp).c_str(), this->data_for_get.c_str());
            v = this->value;
            goto unlock;
        }

        for(int i = 0; i < this->bytes_to_get; ++i) {
            tmp_value |= *((uint8_t*)resp + (this->start_byte + i - 1)) << i*8;
        }

        free(req);
        free(resp);

        v = to_string((int)tmp_value);
    } else {
        v = this->value;
    }

unlock:

    pthread_mutex_unlock(&this->set_get_mutex);

    return v;
}

void Command::init()
{   
    uint32_t value = 0;
    int retry_count = 10;
    b_packet_t *req, *resp;

    this->value = "0";
    req = str_to_pkt(this->data_for_get);

retry:
    retry_count--;
    resp = rt_send_request(this->port, req);

    if(!resp) {
        logger(SM_LOG_ERR,"ERROR INITING COMMAND: = retrying, count = %d...", (10 - retry_count));
        if(retry_count == 0) {
            free(req);
            return;
        }
        usleep(100000);
        goto retry;
    }

    std::string resp_str = pkt_to_str((b_packet_t*)resp);
    std::string req_str = pkt_to_str((b_packet_t*)req);

    if((this->start_byte + this->bytes_to_get - 2) >= resp->size + 3){
        logger(SM_LOG_ERR,"CMD INIT ERROR: WRONG data RCVD, pkt[%s] data_for_get[%s], retrying, count = %d ...", 
                resp_str.c_str(), this->data_for_get.c_str(), (10 - retry_count));
        goto retry;
    }

    for(int i = 0; i < this->bytes_to_get; ++i) {
        value |= *((uint8_t*)resp + (this->start_byte + i - 1)) << i*8;
    }

    free(req);
    free(resp);

    this->value = to_string((int)value);
    logger(SM_LOG_INFO,"INIT_CMD[%d] ---> [%d] req[%s] resp[%s]", 
            this->gid, (int)value, req_str.c_str(), resp_str.c_str());
}

/* Condition class implementation */
Condition::Condition()
{
    /* sets the default timer to 0.0 sec for the checking the condition. */
    this->sevp.sigev_notify = SIGEV_NONE;
    this->step_sevp.sigev_notify = SIGEV_NONE;

    timer_create(CLOCK_REALTIME, &this->sevp, &this->timerid);
    timer_create(CLOCK_REALTIME, &this->step_sevp, &this->step_timerid);

    timeout.it_value.tv_sec = 0;
    timeout.it_value.tv_nsec = 0;
    timeout.it_interval.tv_sec = 0;
    timeout.it_interval.tv_nsec = 0;

    step_timeout.it_value.tv_sec = 0;
    step_timeout.it_value.tv_nsec = 0;
    step_timeout.it_interval.tv_sec = 0;
    step_timeout.it_interval.tv_nsec = 0;
}

void* Condition::start_routine(void* obj)
{
    Parser eval;
    int eval_result;
    Condition* c = (Condition*)obj;
    std::string eval_expr = c->expr;

    pthread_detach(pthread_self());

    /* Extracting 'g*' global IDs from the expression */
    std::vector<unsigned int> gids_str;
    extract_gids(c->expr, gids_str);

    bool timeout_specified = false;
    bool step_timeout_specified = false;
    bool forever = true;

    if(c->step_timeout.it_value.tv_sec != 0 || c->step_timeout.it_value.tv_nsec != 0){
        struct itimerspec t = {0};
        step_timeout_specified = true;
        c->start_timer(c->step_timerid, t);
    }

    if(c->timeout.it_value.tv_sec || c->timeout.it_value.tv_nsec){
        timeout_specified = true;
        c->start_timer(c->timerid, c->timeout);
    }

    if(!timeout_specified && !step_timeout_specified){
        forever = false;
    }

    do {
        /* Reset the expression string and start over. */
        eval_expr = c->expr;

        if(step_timeout_specified){
            struct itimerspec curr_value;
            timer_gettime(c->step_timerid, &curr_value);

            if((!curr_value.it_value.tv_sec && !curr_value.it_value.tv_nsec)){
                c->start_timer(c->step_timerid, c->step_timeout);
            } else {
                nanosleep(&curr_value.it_value, NULL);
                continue;
            }
        }

        c->exit_if_mode_is_off();

        /* find and replace g* string with it's value. */
        replace_ids_to_values(gids_str, eval_expr);

        find_and_replace(eval_expr, "value", c->m->get_value());
        find_and_replace(eval_expr, "off", "0");
        find_and_replace(eval_expr, "on", "1");

        replace_timers(eval_expr);

        eval_result = eval.parse(eval_expr.c_str());
        //logger(SM_LOG_INFO,"GID[%d]#Eval %s: %s Result: %d\n", c->m->gid,
        //c->expr.c_str(), eval_expr.c_str(), eval_result);

        if(eval_result == 1){
            if(timeout_specified){
                if(c->is_timeout(c->timerid)){
                    exec(c->true_cmds, c->m->value, c->m->gid, MODE);
                    c->start_timer(c->timerid, c->timeout);
                }
            } else {
                exec(c->true_cmds, c->m->value, c->m->gid, MODE);
            }
        } else {
            if(timeout_specified){
                /* reset_timeout */
                c->start_timer(c->timerid, c->timeout);
            }
            exec(c->false_cmds, c->m->value, c->m->gid, MODE);
        }

        c->exit_if_mode_is_off();

        if(!forever) 
            c->m->turn_off_mode();
    }
    while(forever);

    pthread_exit(NULL);
}

void Condition::exit_if_mode_is_off()
{
    pthread_mutex_lock(&this->m->set_get_mutex);
    if(this->m->state == "off"){
        pthread_mutex_unlock(&this->m->set_get_mutex);
        pthread_exit(NULL);
    }
    pthread_mutex_unlock(&this->m->set_get_mutex);
}

void Condition::start()
{   
    pthread_create(&this->thread, NULL, &Condition::start_routine,
            static_cast<void*>(this));
}

bool Condition::is_timeout(timer_t &timerid)
{
    struct itimerspec curr_value;

    timer_gettime(timerid, &curr_value);
    return (!curr_value.it_value.tv_sec && !curr_value.it_value.tv_nsec);
}

void Condition::start_timer(timer_t timerid, struct itimerspec &timeout)
{
    timer_settime(timerid, 0, &timeout, NULL);
}

/* Mode class implementation */
Mode::Mode()
{ 
    this->save_attribute = NULL;
    pthread_mutex_init(&this->set_get_mutex, NULL);
    pthread_mutex_init(&this->v_mutex, NULL);
}

void Mode::start()
{   
    /* Executing 'actions'. */
    exec(this->actions, this->value, this->gid, MODE);

    if(this->cnds.size() == 0) {
        this->state = "off";
        logger(SM_LOG_INFO,"Turning 'off' Mode: [%d]", this->gid);
        return;
    }

    this->working_count = this->cnds.size();;

    /* Starting all conditions via threads. */
    for(std::vector<Condition>::iterator it = this->cnds.begin();
            it < this->cnds.end(); ++it) {
        it->m = this;
        it->start();
    }
}

void Mode::set(std::string v)
{
    pthread_mutex_lock(&this->set_get_mutex);
    if(v != "off"){
        if(this->state == "off") {
            this->state = "on";
            if(v != "on")
                this->set_value(v);
            this->start();
        } else {
            if(v != "on")
                this->set_value(v);
        }
    } else
        this->state = "off";

    if(this->save_attribute) {
        this->save_attribute->set_value(this->state);
        save_config();
    }
    pthread_mutex_unlock(&this->set_get_mutex);
}

void Mode::turn_off_mode()
{
    pthread_mutex_lock(&this->set_get_mutex);
    this->working_count--;

    if(this->working_count == 0){
        this->state = "off";
        if(this->save_attribute) {
            this->save_attribute->set_value(this->state);
            save_config();
        }
    }
    pthread_mutex_unlock(&this->set_get_mutex);
}

std::string Mode::get()
{
    std::string v;
    pthread_mutex_lock(&this->set_get_mutex);
    if(this->state == "on"){
        v = "1";
    } else {
        v = "0";
    }
    pthread_mutex_unlock(&this->set_get_mutex);

    return v;
}

void Mode::set_value(std::string v)
{
    pthread_mutex_lock(&this->v_mutex);
    this->value = v;
    pthread_mutex_unlock(&this->v_mutex);
}

std::string Mode::get_value()
{
    pthread_mutex_lock(&this->v_mutex);
    std::string v;
    v = this->value ;
    pthread_mutex_unlock(&this->v_mutex);
    return v;
}

/* Timer class implementation */
void* Timer::start_routine(void* obj)
{
    Timer* t = (Timer*)obj;

    pthread_detach(pthread_self());
    pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);

    t->start_timer();
    while(true) {
        struct itimerspec curr_value;
        timer_gettime(t->timerid, &curr_value);

        if((!curr_value.it_value.tv_sec && !curr_value.it_value.tv_nsec)){
            t->start_timer();
        } else {
            pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
            nanosleep(&curr_value.it_value, NULL);
            pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
            continue;
        }

        pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
        exec(t->actions, to_string(t->timeout_f), t->gid, TIMER);

        t->start_timer();
        pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
    }

    pthread_exit(NULL);
}

void Timer::start()
{   
    pthread_create(&this->thread, NULL, &Timer::start_routine,
            static_cast<void*>(this));
}

void Timer::stop()
{   
    if(pthread_self() == this->thread) {
        pthread_mutex_unlock(&this->set_get_mutex);
        pthread_exit(NULL);
    } else {
        pthread_cancel(this->thread);
    }
}

void Timer::set(std::string v)
{
    pthread_mutex_lock(&this->set_get_mutex);
    if(v != "off") {
        if(this->state == "off") {
            this->state = "on";
            if(v != "on") {
                this->set_value(v);
            } else if (this->value[0] == '(') {
                std::map<unsigned int, Base*>::iterator b_it;
                int gid = atoi(this->value.substr(2).c_str());
                b_it = gids.find(gid);
                if(b_it == gids.end()){
                    logger(SM_LOG_ERR, "ERROR, wrong gid in the Timer's timeout, gid=%d, " 
                            "or maybe constant value is in the (), pls remove () parentheses",gid);
                    exit(-1);
                }
                this->set_value(gids[gid]->get());
            }
            this->start();
        } else {
            if(v != "on" && this->get_value() != v){
                this->set_value(v);
                logger(SM_LOG_INFO,"the timer's [%d] value is changed to '%s'",
                        this->gid, v.c_str());
            }
        }
    } else {
        if(this->state != "off") {
            this->state = "off";
            this->stop();
        }
    }
    pthread_mutex_unlock(&this->set_get_mutex);
}

std::string Timer::get()
{
    std::string v;
    pthread_mutex_lock(&this->set_get_mutex);
    if(this->state == "on"){
        v = "1";
    } else {
        v = "0";
    }
    pthread_mutex_unlock(&this->set_get_mutex);

    return v;
}

void Timer::set_value(std::string v)
{
    pthread_mutex_lock(&this->v_mutex);
    float f = atof(v.c_str());
    this->timeout_f = f;
    float fractional;
    float integral;
    fractional = modff(f, &integral);
    this->timeout.it_value.tv_sec = (int)integral;
    this->timeout.it_value.tv_nsec = (long)lrintf((fractional) * 1000) * 1000000;
    this->timeout.it_interval.tv_sec = 0;
    this->timeout.it_interval.tv_nsec = 0;
    pthread_mutex_unlock(&this->v_mutex);
}

std::string Timer::get_value()
{
    std::string v;
    pthread_mutex_lock(&this->v_mutex);
    v = this->value ;
    pthread_mutex_unlock(&this->v_mutex);
    return v;
}

bool Timer::is_timeout()
{
    struct itimerspec curr_value;

    timer_gettime(this->timerid, &curr_value);
    return (!curr_value.it_value.tv_sec && !curr_value.it_value.tv_nsec);
}

void Timer::start_timer()
{
    pthread_mutex_lock(&this->v_mutex);
    timer_settime(this->timerid, 0, &this->timeout, NULL);
    pthread_mutex_unlock(&this->v_mutex);
}

void Fingerprint::set(std::string value)
{
    int v = -1;
    pthread_mutex_lock(&this->set_get_mutex);
    switch(this->cmd_type) {
        case FP_ADD_USER:
            v = fp_add_user(gids[this->uname_gid]->get(), gids[this->ulevel_gid]->get());
            break;
        case FP_IDENTIFY_USER:
            v = fp_identify_user_by_scan();
            break;
        case FP_DELETE_USER:
            v = fp_delete_user_by_id(value);
            break;
        case FP_DELETE_ALL_USERS:
            v = fp_delete_all_users();
            break;
        case FP_GET_USER_LEVEL:
            for(std::map<int, User>::iterator it = users.begin(); it != users.end(); ++it)
                if(it->first == atoi(value.c_str()))
                    v = atoi(it->second.level.c_str());
            break;
        case FP_CHANGE_USER_LEVEL: {
                v = fp_change_user_level(gids[this->ulevel_gid]->get(), 
                        gids[atoi(value.c_str())]->get());
            }
            break;
        default:
            break;
    }
    this->value = to_string(v);
    pthread_mutex_unlock(&this->set_get_mutex);
}

std::string Fingerprint::get()
{
    std::string v;
    pthread_mutex_lock(&this->set_get_mutex);
    v = this->value;
    pthread_mutex_unlock(&this->set_get_mutex);
    return v;
}

std::string Function::get()
{
    return "NULL"; // TODO:
}

void Function::set(std::string value)
{
    Parser eval;
    int eval_result;
    std::string eval_expr = this->expr;

    /* find and replace g* string with it's value. */
    replace_ids_to_values(this->expr_gids, eval_expr);

    find_and_replace(eval_expr, "value", value);
    find_and_replace(eval_expr, "off", "0");
    find_and_replace(eval_expr, "on", "1");

    replace_timers(eval_expr);

    eval_result = eval.parse(eval_expr.c_str());

    if(eval_result == 1){
        exec(this->true_cmds, value, this->gid, FUNCTION);
    } else {
        exec(this->false_cmds, value, this->gid, FUNCTION);
    }
}

void SysSleep::set(std::string secs)
{
    double seconds = atof(secs.c_str());
    logger(SM_LOG_INFO,"Sleeping %.03f seconds ...", seconds);
    usleep((useconds_t)(seconds * 1000000));
    return;
}

std::string SysSleep::get()
{
    return "SLEEP";
}

void Ping::set(std::string v)
{
    pthread_mutex_lock(&this->set_get_mutex);
    if(v == "1") {
        std::string ping_str = "ping -c 1 -W 1 " + this->ip_address + " &> /dev/null";
        if(system(ping_str.c_str()) == 0) {
            this->state = true;
        } else {
            this->state = false;
        }
        logger(SM_LOG_INFO,"PING[%d] ---> IP [%s] STATE [%s]", 
                this->gid, this->ip_address.c_str(), this->state ? "OK" : "FAILED");
    }
    else {
        this->state = false;
    }
    pthread_mutex_unlock(&this->set_get_mutex);
    return;
}

std::string Ping::get()
{
    return this->state ? "1" : "0";
}
